home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-25  |  64.3 KB  |  2,771 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * ui.c: functions that handle the user interface.
  12.  * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
  13.  *    before the machine specific stuff (mch_*) so that we can call the GUI
  14.  *    stuff instead if the GUI is running.
  15.  * 2. Clipboard stuff.
  16.  * 3. Input buffer stuff.
  17.  */
  18.  
  19. #include "vim.h"
  20.  
  21.     void
  22. ui_write(s, len)
  23.     char_u  *s;
  24.     int        len;
  25. {
  26. #ifdef FEAT_GUI
  27.     if (gui.in_use && !gui.dying)
  28.     {
  29.     gui_write(s, len);
  30.     if (p_wd)
  31.         gui_wait_for_chars(p_wd);
  32.     return;
  33.     }
  34. #endif
  35. #ifndef NO_CONSOLE
  36.     /* Don't output anything in silent mode ("ex -s") */
  37.     if (!silent_mode)
  38.     {
  39. #ifdef FEAT_MBYTE
  40.     char_u    *tofree = NULL;
  41.  
  42.     if (output_conv.vc_type != CONV_NONE)
  43.     {
  44.         /* Convert characters from 'encoding' to 'termencoding'. */
  45.         tofree = string_convert(&output_conv, s, &len);
  46.         if (tofree != NULL)
  47.         s = tofree;
  48.     }
  49. #endif
  50.  
  51.     mch_write(s, len);
  52.  
  53. #ifdef FEAT_MBYTE
  54.     if (output_conv.vc_type != CONV_NONE)
  55.         vim_free(tofree);
  56. #endif
  57.     }
  58. #endif
  59. }
  60.  
  61. #if (defined(FEAT_GUI) && defined(UNIX)) || defined(PROTO)
  62. /*
  63.  * When executing an external program, there may be some typed characters that
  64.  * are not consumed by it.  Give them back to ui_inchar() and they are stored
  65.  * here for the next call.
  66.  */
  67. static char_u *ta_str = NULL;
  68. static int ta_off;    /* offset for next char to use when ta_str != NULL */
  69. static int ta_len;    /* length of ta_str when it's not NULL*/
  70.  
  71.     void
  72. ui_inchar_undo(s, len)
  73.     char_u    *s;
  74.     int        len;
  75. {
  76.     char_u  *new;
  77.     int        newlen;
  78.  
  79.     newlen = len;
  80.     if (ta_str != NULL)
  81.     newlen += ta_len - ta_off;
  82.     new = alloc(newlen);
  83.     if (new != NULL)
  84.     {
  85.     if (ta_str != NULL)
  86.     {
  87.         mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off));
  88.         mch_memmove(new + ta_len - ta_off, s, (size_t)len);
  89.         vim_free(ta_str);
  90.     }
  91.     else
  92.         mch_memmove(new, s, (size_t)len);
  93.     ta_str = new;
  94.     ta_len = newlen;
  95.     ta_off = 0;
  96.     }
  97. }
  98. #endif
  99.  
  100. /*
  101.  * ui_inchar(): low level input funcion.
  102.  * Get characters from the keyboard.
  103.  * Return the number of characters that are available.
  104.  * If "wtime" == 0 do not wait for characters.
  105.  * If "wtime" == -1 wait forever for characters.
  106.  * If "wtime" > 0 wait "wtime" milliseconds for a character.
  107.  */
  108.     int
  109. ui_inchar(buf, maxlen, wtime)
  110.     char_u    *buf;
  111.     int        maxlen;
  112.     long    wtime;        /* don't use "time", MIPS cannot handle it */
  113. {
  114.     int        retval = 0;
  115.  
  116. #if defined(FEAT_GUI) && defined(UNIX)
  117.     /*
  118.      * Use the typeahead if there is any.
  119.      */
  120.     if (ta_str != NULL)
  121.     {
  122.     if (maxlen >= ta_len - ta_off)
  123.     {
  124.         mch_memmove(buf, ta_str + ta_off, (size_t)ta_len);
  125.         vim_free(ta_str);
  126.         ta_str = NULL;
  127.         return ta_len;
  128.     }
  129.     mch_memmove(buf, ta_str + ta_off, (size_t)maxlen);
  130.     ta_off += maxlen;
  131.     return maxlen;
  132.     }
  133. #endif
  134.  
  135. #ifdef NO_CONSOLE_INPUT
  136.     /* Don't wait for character input when the window hasn't been opened yet.
  137.      * Must return something, otherwise we'll loop forever.  */
  138.     if (no_console_input())
  139.     {
  140.     buf[0] = CR;
  141.     return 1;
  142.     }
  143. #endif
  144.  
  145.     /* When doing a blocking wait there is no need for CTRL-C to interrupt
  146.      * something, don't let it set got_int when it was mapped. */
  147.     if (mapped_ctrl_c && (wtime == -1 || wtime > 100L))
  148.     ctrl_c_interrupts = FALSE;
  149.  
  150. #ifdef FEAT_GUI
  151.     if (gui.in_use)
  152.     {
  153.     if (gui_wait_for_chars(wtime))
  154.         retval = read_from_input_buf(buf, (long)maxlen);
  155.     }
  156. #endif
  157. #ifndef NO_CONSOLE
  158. # ifdef FEAT_GUI
  159.     else
  160. # endif
  161.     retval = mch_inchar(buf, maxlen, wtime);
  162. #endif
  163.  
  164.     ctrl_c_interrupts = TRUE;
  165.  
  166.     return retval;
  167. }
  168.  
  169. /*
  170.  * return non-zero if a character is available
  171.  */
  172.     int
  173. ui_char_avail()
  174. {
  175. #ifdef FEAT_GUI
  176.     if (gui.in_use)
  177.     {
  178.     gui_mch_update();
  179.     return !vim_is_input_buf_empty();
  180.     }
  181. #endif
  182. #ifndef NO_CONSOLE
  183. # ifdef NO_CONSOLE_INPUT
  184.     if (no_console_input())
  185.     return 0;
  186. # endif
  187.     return mch_char_avail();
  188. #else
  189.     return 0;
  190. #endif
  191. }
  192.  
  193. /*
  194.  * Delay for the given number of milliseconds.    If ignoreinput is FALSE then we
  195.  * cancel the delay if a key is hit.
  196.  */
  197.     void
  198. ui_delay(msec, ignoreinput)
  199.     long    msec;
  200.     int        ignoreinput;
  201. {
  202. #ifdef FEAT_GUI
  203.     if (gui.in_use && !ignoreinput)
  204.     gui_wait_for_chars(msec);
  205.     else
  206. #endif
  207.     mch_delay(msec, ignoreinput);
  208. }
  209.  
  210. /*
  211.  * If the machine has job control, use it to suspend the program,
  212.  * otherwise fake it by starting a new shell.
  213.  * When running the GUI iconify the window.
  214.  */
  215.     void
  216. ui_suspend()
  217. {
  218. #ifdef FEAT_GUI
  219.     if (gui.in_use)
  220.     {
  221.     gui_mch_iconify();
  222.     return;
  223.     }
  224. #endif
  225.     mch_suspend();
  226. }
  227.  
  228. #if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO) || defined(__BEOS__)
  229. /*
  230.  * When the OS can't really suspend, call this function to start a shell.
  231.  * This is never called in the GUI.
  232.  */
  233.     void
  234. suspend_shell()
  235. {
  236.     if (*p_sh == NUL)
  237.     EMSG(_(e_shellempty));
  238.     else
  239.     {
  240.     MSG_PUTS(_("new shell started\n"));
  241.     do_shell(NULL, 0);
  242.     }
  243. }
  244. #endif
  245.  
  246. /*
  247.  * Try to get the current Vim shell size.  Put the result in Rows and Columns.
  248.  * Use the new sizes as defaults for 'columns' and 'lines'.
  249.  * Return OK when size could be determined, FAIL otherwise.
  250.  */
  251.     int
  252. ui_get_shellsize()
  253. {
  254.     int        retval;
  255.  
  256. #ifdef FEAT_GUI
  257.     if (gui.in_use)
  258.     retval = gui_get_shellsize();
  259.     else
  260. #endif
  261.     retval = mch_get_shellsize();
  262.  
  263.     check_shellsize();
  264.  
  265.     /* adjust the default for 'lines' and 'columns' */
  266.     if (retval == OK)
  267.     {
  268.     set_number_default("lines", Rows);
  269.     set_number_default("columns", Columns);
  270.     }
  271.     return retval;
  272. }
  273.  
  274. /*
  275.  * Set the size of the Vim shell according to Rows and Columns, if possible.
  276.  * The gui_set_shellsize() or mch_set_shellsize() function will try to set the
  277.  * new size.  If this is not possible, it will adjust Rows and Columns.
  278.  */
  279. /*ARGSUSED*/
  280.     void
  281. ui_set_shellsize(mustset)
  282.     int        mustset;    /* set by the user */
  283. {
  284. #ifdef FEAT_GUI
  285.     if (gui.in_use)
  286.     gui_set_shellsize(mustset,
  287. # ifdef WIN3264
  288.         TRUE
  289. # else
  290.         FALSE
  291. # endif
  292.         );
  293.     else
  294. #endif
  295.     mch_set_shellsize();
  296. }
  297.  
  298. /*
  299.  * Called when Rows and/or Columns changed.  Adjust scroll region and mouse
  300.  * region.
  301.  */
  302.     void
  303. ui_new_shellsize()
  304. {
  305.     if (full_screen && !exiting)
  306.     {
  307. #ifdef FEAT_GUI
  308.     if (gui.in_use)
  309.         gui_new_shellsize();
  310.     else
  311. #endif
  312.         mch_new_shellsize();
  313.     }
  314. }
  315.  
  316.     void
  317. ui_breakcheck()
  318. {
  319. #ifdef FEAT_GUI
  320.     if (gui.in_use)
  321.     gui_mch_update();
  322.     else
  323. #endif
  324.     mch_breakcheck();
  325. }
  326.  
  327. /*****************************************************************************
  328.  * Functions for copying and pasting text between applications.
  329.  * This is always included in a GUI version, but may also be included when the
  330.  * clipboard and mouse is available to a terminal version such as xterm.
  331.  * Note: there are some more functions in ops.c that handle selection stuff.
  332.  *
  333.  * Also note that the majority of functions here deal with the X 'primary'
  334.  * (visible - for Visual mode use) selection, and only that. There are no
  335.  * versions of these for the 'clipboard' selection, as Visual mode has no use
  336.  * for them.
  337.  */
  338.  
  339. #if defined(FEAT_CLIPBOARD) || defined(PROTO)
  340.  
  341. /*
  342.  * Selection stuff using Visual mode, for cutting and pasting text to other
  343.  * windows.
  344.  */
  345.  
  346. /*
  347.  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
  348.  * is included, but the clipboard can not be used, or TRUE if the clipboard can
  349.  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
  350.  * the GUI starts.
  351.  */
  352.     void
  353. clip_init(can_use)
  354.     int        can_use;
  355. {
  356.     VimClipboard *cb;
  357.  
  358.     cb = &clip_star;
  359.     for (;;)
  360.     {
  361.     cb->available  = can_use;
  362.     cb->owned      = FALSE;
  363.     cb->start.lnum = 0;
  364.     cb->start.col  = 0;
  365.     cb->end.lnum   = 0;
  366.     cb->end.col    = 0;
  367.     cb->state      = SELECT_CLEARED;
  368.  
  369.     if (cb == &clip_plus)
  370.         break;
  371.     cb = &clip_plus;
  372.     }
  373. }
  374.  
  375. /*
  376.  * Check whether the VIsual area has changed, and if so try to become the owner
  377.  * of the selection, and free any old converted selection we may still have
  378.  * lying around.  If the VIsual mode has ended, make a copy of what was
  379.  * selected so we can still give it to others.    Will probably have to make sure
  380.  * this is called whenever VIsual mode is ended.
  381.  */
  382.     void
  383. clip_update_selection()
  384. {
  385.     pos_T    start, end;
  386.  
  387.     /* If visual mode is only due to a redo command ("."), then ignore it */
  388.     if (!redo_VIsual_busy && VIsual_active)
  389.     {
  390.     if (lt(VIsual, curwin->w_cursor))
  391.     {
  392.         start = VIsual;
  393.         end = curwin->w_cursor;
  394. #ifdef FEAT_MBYTE
  395.         if (has_mbyte)
  396.         end.col += (*mb_ptr2len_check)(ml_get_cursor()) - 1;
  397. #endif
  398.     }
  399.     else
  400.     {
  401.         start = curwin->w_cursor;
  402.         end = VIsual;
  403.     }
  404.     if (!equal(clip_star.start, start) || !equal(clip_star.end, end)
  405.                         || clip_star.vmode != VIsual_mode)
  406.     {
  407.         clip_clear_selection();
  408.         clip_star.start = start;
  409.         clip_star.end = end;
  410.         clip_star.vmode = VIsual_mode;
  411.         clip_free_selection(&clip_star);
  412.         clip_own_selection(&clip_star);
  413.         clip_gen_set_selection(&clip_star);
  414.     }
  415.     }
  416. }
  417.  
  418.     void
  419. clip_own_selection(cbd)
  420.     VimClipboard    *cbd;
  421. {
  422.     /*
  423.      * Also want to check somehow that we are reading from the keyboard rather
  424.      * than a mapping etc.
  425.      */
  426.     if (!cbd->owned && cbd->available)
  427.     {
  428.     cbd->owned = (clip_gen_own_selection(cbd) == OK);
  429. #ifdef FEAT_X11
  430.     if (cbd == &clip_star)
  431.     {
  432.         /* May have to show a different kind of highlighting for the selected
  433.          * area.  There is no specific redraw command for this, just redraw
  434.          * all windows on the current buffer. */
  435.         if (cbd->owned
  436.             && get_real_state() == VISUAL
  437.             && clip_isautosel()
  438.             && hl_attr(HLF_V) != hl_attr(HLF_VNC))
  439.         redraw_curbuf_later(INVERTED_ALL);
  440.     }
  441. #endif
  442.     }
  443. }
  444.  
  445.     void
  446. clip_lose_selection(cbd)
  447.     VimClipboard    *cbd;
  448. {
  449. #ifdef FEAT_X11
  450.     int        was_owned = cbd->owned;
  451. #endif
  452.     int     visual_selection = (cbd == &clip_star);
  453.  
  454.     clip_free_selection(cbd);
  455.     cbd->owned = FALSE;
  456.     if (visual_selection)
  457.     clip_clear_selection();
  458.     clip_gen_lose_selection(cbd);
  459. #ifdef FEAT_X11
  460.     if (visual_selection)
  461.     {
  462.     /* May have to show a different kind of highlighting for the selected
  463.      * area.  There is no specific redraw command for this, just redraw all
  464.      * windows on the current buffer. */
  465.     if (was_owned
  466.         && get_real_state() == VISUAL
  467.         && clip_isautosel()
  468.         && hl_attr(HLF_V) != hl_attr(HLF_VNC))
  469.     {
  470.         update_curbuf(INVERTED_ALL);
  471.         setcursor();
  472.         cursor_on();
  473.         out_flush();
  474.     }
  475.     }
  476. #endif
  477. }
  478.  
  479.     void
  480. clip_copy_selection()
  481. {
  482.     if (VIsual_active && clip_star.available)
  483.     {
  484.     if (clip_isautosel())
  485.         clip_update_selection();
  486.     clip_free_selection(&clip_star);
  487.     clip_own_selection(&clip_star);
  488.     if (clip_star.owned)
  489.         clip_get_selection(&clip_star);
  490.     clip_gen_set_selection(&clip_star);
  491.     }
  492. }
  493.  
  494. /*
  495.  * Called when Visual mode is ended: update the selection.
  496.  */
  497.     void
  498. clip_auto_select()
  499. {
  500.     if (clip_isautosel())
  501.     clip_copy_selection();
  502. }
  503.  
  504. /*
  505.  * Return TRUE if automatic selection of Visual area is desired.
  506.  */
  507.     int
  508. clip_isautosel()
  509. {
  510.     return (
  511. #ifdef FEAT_GUI
  512.         gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
  513. #endif
  514.         clip_autoselect);
  515. }
  516.  
  517.  
  518. /*
  519.  * Stuff for general mouse selection, without using Visual mode.
  520.  */
  521.  
  522. static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));
  523. static void clip_invert_area __ARGS((int, int, int, int, int how));
  524. static void clip_invert_rectangle __ARGS((int row, int col, int height, int width, int invert));
  525. static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
  526. static int  clip_get_line_end __ARGS((int));
  527. static void clip_update_modeless_selection __ARGS((VimClipboard *, int, int,
  528.                             int, int));
  529.  
  530. /* flags for clip_invert_area() */
  531. #define CLIP_CLEAR    1
  532. #define CLIP_SET    2
  533. #define CLIP_TOGGLE    3
  534.  
  535. /*
  536.  * Start, continue or end a modeless selection.  Used when editing the
  537.  * command-line and in the cmdline window.
  538.  */
  539.     void
  540. clip_modeless(button, is_click, is_drag)
  541.     int        button;
  542.     int        is_click;
  543.     int        is_drag;
  544. {
  545.     int        repeat;
  546.  
  547.     repeat = ((clip_star.mode == SELECT_MODE_CHAR
  548.         || clip_star.mode == SELECT_MODE_LINE)
  549.                           && (mod_mask & MOD_MASK_2CLICK))
  550.         || (clip_star.mode == SELECT_MODE_WORD
  551.                          && (mod_mask & MOD_MASK_3CLICK));
  552.     if (is_click && button == MOUSE_RIGHT)
  553.     {
  554.     /* Right mouse button: If there was no selection, start one.
  555.      * Otherwise extend the existing selection. */
  556.     if (clip_star.state == SELECT_CLEARED)
  557.         clip_start_selection(mouse_col, mouse_row, FALSE);
  558.     clip_process_selection(button, mouse_col, mouse_row, repeat);
  559.     }
  560.     else if (is_click)
  561.     clip_start_selection(mouse_col, mouse_row, repeat);
  562.     else if (is_drag)
  563.     clip_process_selection(button, mouse_col, mouse_row, repeat);
  564.     else /* release */
  565.     clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
  566. }
  567.  
  568. /*
  569.  * Compare two screen positions ala strcmp()
  570.  */
  571.     static int
  572. clip_compare_pos(row1, col1, row2, col2)
  573.     int        row1;
  574.     int        col1;
  575.     int        row2;
  576.     int        col2;
  577. {
  578.     if (row1 > row2) return(1);
  579.     if (row1 < row2) return(-1);
  580.     if (col1 > col2) return(1);
  581.     if (col1 < col2) return(-1);
  582.              return(0);
  583. }
  584.  
  585. /*
  586.  * Start the selection
  587.  */
  588.     void
  589. clip_start_selection(col, row, repeated_click)
  590.     int        col;
  591.     int        row;
  592.     int        repeated_click;
  593. {
  594.     VimClipboard    *cb = &clip_star;
  595.  
  596.     if (cb->state == SELECT_DONE)
  597.     clip_clear_selection();
  598.  
  599.     row = check_row(row);
  600.     col = check_col(col);
  601. #ifdef FEAT_MBYTE
  602.     col = mb_fix_col(col, row);
  603. #endif
  604.  
  605.     cb->start.lnum  = row;
  606.     cb->start.col   = col;
  607.     cb->end        = cb->start;
  608.     cb->origin_row  = (short_u)cb->start.lnum;
  609.     cb->state        = SELECT_IN_PROGRESS;
  610.  
  611.     if (repeated_click)
  612.     {
  613.     if (++cb->mode > SELECT_MODE_LINE)
  614.         cb->mode = SELECT_MODE_CHAR;
  615.     }
  616.     else
  617.     cb->mode = SELECT_MODE_CHAR;
  618.  
  619. #ifdef FEAT_GUI
  620.     /* clear the cursor until the selection is made */
  621.     if (gui.in_use)
  622.     gui_undraw_cursor();
  623. #endif
  624.  
  625.     switch (cb->mode)
  626.     {
  627.     case SELECT_MODE_CHAR:
  628.         cb->origin_start_col = cb->start.col;
  629.         cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
  630.         break;
  631.  
  632.     case SELECT_MODE_WORD:
  633.         clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
  634.         cb->origin_start_col = cb->word_start_col;
  635.         cb->origin_end_col     = cb->word_end_col;
  636.  
  637.         clip_invert_area((int)cb->start.lnum, cb->word_start_col,
  638.                 (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
  639.         cb->start.col = cb->word_start_col;
  640.         cb->end.col   = cb->word_end_col;
  641.         break;
  642.  
  643.     case SELECT_MODE_LINE:
  644.         clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
  645.                 (int)Columns, CLIP_SET);
  646.         cb->start.col = 0;
  647.         cb->end.col   = Columns;
  648.         break;
  649.     }
  650.  
  651.     cb->prev = cb->start;
  652.  
  653. #ifdef DEBUG_SELECTION
  654.     printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
  655. #endif
  656. }
  657.  
  658. /*
  659.  * Continue processing the selection
  660.  */
  661.     void
  662. clip_process_selection(button, col, row, repeated_click)
  663.     int        button;
  664.     int        col;
  665.     int        row;
  666.     int_u    repeated_click;
  667. {
  668.     VimClipboard    *cb = &clip_star;
  669.     int            diff;
  670.     int            slen = 1;    /* cursor shape width */
  671.  
  672.     if (button == MOUSE_RELEASE)
  673.     {
  674.     /* Check to make sure we have something selected */
  675.     if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
  676.     {
  677. #ifdef FEAT_GUI
  678.         if (gui.in_use)
  679.         gui_update_cursor(FALSE, FALSE);
  680. #endif
  681.         cb->state = SELECT_CLEARED;
  682.         return;
  683.     }
  684.  
  685. #ifdef DEBUG_SELECTION
  686.     printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
  687.         cb->start.col, cb->end.lnum, cb->end.col);
  688. #endif
  689.     if (clip_isautosel()
  690.         || (
  691. #ifdef FEAT_GUI
  692.             gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
  693. #endif
  694.             clip_autoselectml))
  695.         clip_copy_modeless_selection(FALSE);
  696. #ifdef FEAT_GUI
  697.     if (gui.in_use)
  698.         gui_update_cursor(FALSE, FALSE);
  699. #endif
  700.  
  701.     cb->state = SELECT_DONE;
  702.     return;
  703.     }
  704.  
  705.     row = check_row(row);
  706.     col = check_col(col);
  707. #ifdef FEAT_MBYTE
  708.     col = mb_fix_col(col, row);
  709. #endif
  710.  
  711.     if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
  712.     return;
  713.  
  714.     /*
  715.      * When extending the selection with the right mouse button, swap the
  716.      * start and end if the position is before half the selection
  717.      */
  718.     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
  719.     {
  720.     /*
  721.      * If the click is before the start, or the click is inside the
  722.      * selection and the start is the closest side, set the origin to the
  723.      * end of the selection.
  724.      */
  725.     if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
  726.         || (clip_compare_pos(row, col,
  727.                        (int)cb->end.lnum, cb->end.col) < 0
  728.             && (((cb->start.lnum == cb->end.lnum
  729.                 && cb->end.col - col > col - cb->start.col))
  730.             || ((diff = (cb->end.lnum - row) -
  731.                            (row - cb->start.lnum)) > 0
  732.                 || (diff == 0 && col < (int)(cb->start.col +
  733.                              cb->end.col) / 2)))))
  734.     {
  735.         cb->origin_row = (short_u)cb->end.lnum;
  736.         cb->origin_start_col = cb->end.col - 1;
  737.         cb->origin_end_col = cb->end.col;
  738.     }
  739.     else
  740.     {
  741.         cb->origin_row = (short_u)cb->start.lnum;
  742.         cb->origin_start_col = cb->start.col;
  743.         cb->origin_end_col = cb->start.col;
  744.     }
  745.     if (cb->mode == SELECT_MODE_WORD && !repeated_click)
  746.         cb->mode = SELECT_MODE_CHAR;
  747.     }
  748.  
  749.     /* set state, for when using the right mouse button */
  750.     cb->state = SELECT_IN_PROGRESS;
  751.  
  752. #ifdef DEBUG_SELECTION
  753.     printf("Selection extending to (%d,%d)\n", row, col);
  754. #endif
  755.  
  756.     if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
  757.     cb->mode = SELECT_MODE_CHAR;
  758.  
  759.     switch (cb->mode)
  760.     {
  761.     case SELECT_MODE_CHAR:
  762.         /* If we're on a different line, find where the line ends */
  763.         if (row != cb->prev.lnum)
  764.         cb->word_end_col = clip_get_line_end(row);
  765.  
  766.         /* See if we are before or after the origin of the selection */
  767.         if (clip_compare_pos(row, col, cb->origin_row,
  768.                            cb->origin_start_col) >= 0)
  769.         {
  770.         if (col >= (int)cb->word_end_col)
  771.             clip_update_modeless_selection(cb, cb->origin_row,
  772.                 cb->origin_start_col, row, (int)Columns);
  773.         else
  774.         {
  775. #ifdef FEAT_MBYTE
  776.             if (has_mbyte && mb_lefthalve(row, col))
  777.             slen = 2;
  778. #endif
  779.             clip_update_modeless_selection(cb, cb->origin_row,
  780.                 cb->origin_start_col, row, col + slen);
  781.         }
  782.         }
  783.         else
  784.         {
  785. #ifdef FEAT_MBYTE
  786.         if (has_mbyte
  787.             && mb_lefthalve(cb->origin_row, cb->origin_start_col))
  788.             slen = 2;
  789. #endif
  790.         if (col >= (int)cb->word_end_col)
  791.             clip_update_modeless_selection(cb, row, cb->word_end_col,
  792.                 cb->origin_row, cb->origin_start_col + slen);
  793.         else
  794.             clip_update_modeless_selection(cb, row, col,
  795.                 cb->origin_row, cb->origin_start_col + slen);
  796.         }
  797.         break;
  798.  
  799.     case SELECT_MODE_WORD:
  800.         /* If we are still within the same word, do nothing */
  801.         if (row == cb->prev.lnum && col >= (int)cb->word_start_col
  802.             && col < (int)cb->word_end_col && !repeated_click)
  803.         return;
  804.  
  805.         /* Get new word boundaries */
  806.         clip_get_word_boundaries(cb, row, col);
  807.  
  808.         /* Handle being after the origin point of selection */
  809.         if (clip_compare_pos(row, col, cb->origin_row,
  810.             cb->origin_start_col) >= 0)
  811.         clip_update_modeless_selection(cb, cb->origin_row,
  812.             cb->origin_start_col, row, cb->word_end_col);
  813.         else
  814.         clip_update_modeless_selection(cb, row, cb->word_start_col,
  815.             cb->origin_row, cb->origin_end_col);
  816.         break;
  817.  
  818.     case SELECT_MODE_LINE:
  819.         if (row == cb->prev.lnum && !repeated_click)
  820.         return;
  821.  
  822.         if (clip_compare_pos(row, col, cb->origin_row,
  823.             cb->origin_start_col) >= 0)
  824.         clip_update_modeless_selection(cb, cb->origin_row, 0, row,
  825.             (int)Columns);
  826.         else
  827.         clip_update_modeless_selection(cb, row, 0, cb->origin_row,
  828.             (int)Columns);
  829.         break;
  830.     }
  831.  
  832.     cb->prev.lnum = row;
  833.     cb->prev.col  = col;
  834.  
  835. #ifdef DEBUG_SELECTION
  836.     printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
  837.         cb->start.col, cb->end.lnum, cb->end.col);
  838. #endif
  839. }
  840.  
  841. #if 0 /* not used */
  842. /*
  843.  * Called after an Expose event to redraw the selection
  844.  */
  845.     void
  846. clip_redraw_selection(x, y, w, h)
  847.     int        x;
  848.     int        y;
  849.     int        w;
  850.     int        h;
  851. {
  852.     VimClipboard    *cb = &clip_star;
  853.     int            row1, col1, row2, col2;
  854.     int            row;
  855.     int            start;
  856.     int            end;
  857.  
  858.     if (cb->state == SELECT_CLEARED)
  859.     return;
  860.  
  861.     row1 = check_row(Y_2_ROW(y));
  862.     col1 = check_col(X_2_COL(x));
  863.     row2 = check_row(Y_2_ROW(y + h - 1));
  864.     col2 = check_col(X_2_COL(x + w - 1));
  865.  
  866.     /* Limit the rows that need to be re-drawn */
  867.     if (cb->start.lnum > row1)
  868.     row1 = cb->start.lnum;
  869.     if (cb->end.lnum < row2)
  870.     row2 = cb->end.lnum;
  871.  
  872.     /* Look at each row that might need to be re-drawn */
  873.     for (row = row1; row <= row2; row++)
  874.     {
  875.     /* For the first selection row, use the starting selection column */
  876.     if (row == cb->start.lnum)
  877.         start = cb->start.col;
  878.     else
  879.         start = 0;
  880.  
  881.     /* For the last selection row, use the ending selection column */
  882.     if (row == cb->end.lnum)
  883.         end = cb->end.col;
  884.     else
  885.         end = Columns;
  886.  
  887.     if (col1 > start)
  888.         start = col1;
  889.  
  890.     if (col2 < end)
  891.         end = col2 + 1;
  892.  
  893.     if (end > start)
  894.         gui_mch_invert_rectangle(row, start, 1, end - start);
  895.     }
  896. }
  897. #endif
  898.  
  899. # if defined(FEAT_GUI) || defined(PROTO)
  900. /*
  901.  * Redraw part of the selection if character at "row,col" is inside of it.
  902.  * Only used for the GUI.
  903.  */
  904.     void
  905. clip_may_redraw_selection(row, col, len)
  906.     int        row, col;
  907.     int        len;
  908. {
  909.     int        start = col;
  910.     int        end = col + len;
  911.  
  912.     if (clip_star.state != SELECT_CLEARED
  913.         && row >= clip_star.start.lnum
  914.         && row <= clip_star.end.lnum)
  915.     {
  916.     if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
  917.         start = clip_star.start.col;
  918.     if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
  919.         end = clip_star.end.col;
  920.     if (end > start)
  921.         clip_invert_area(row, start, row, end, 0);
  922.     }
  923. }
  924. # endif
  925.  
  926. /*
  927.  * Called from outside to clear selected region from the display
  928.  */
  929.     void
  930. clip_clear_selection()
  931. {
  932.     VimClipboard    *cb = &clip_star;
  933.  
  934.     if (cb->state == SELECT_CLEARED)
  935.     return;
  936.  
  937.     clip_invert_area((int)cb->start.lnum, cb->start.col, (int)cb->end.lnum,
  938.                              cb->end.col, CLIP_CLEAR);
  939.     cb->state = SELECT_CLEARED;
  940. }
  941.  
  942. /*
  943.  * Clear the selection if any lines from "row1" to "row2" are inside of it.
  944.  */
  945.     void
  946. clip_may_clear_selection(row1, row2)
  947.     int    row1, row2;
  948. {
  949.     if (clip_star.state == SELECT_DONE
  950.         && row2 >= clip_star.start.lnum
  951.         && row1 <= clip_star.end.lnum)
  952.     clip_clear_selection();
  953. }
  954.  
  955. /*
  956.  * Called before the screen is scrolled up or down.  Adjusts the line numbers
  957.  * of the selection.  Call with big number when clearing the screen.
  958.  */
  959.     void
  960. clip_scroll_selection(rows)
  961.     int        rows;        /* negative for scroll down */
  962. {
  963.     int        lnum;
  964.  
  965.     if (clip_star.state == SELECT_CLEARED)
  966.     return;
  967.  
  968.     lnum = clip_star.start.lnum - rows;
  969.     if (lnum <= 0)
  970.     clip_star.start.lnum = 0;
  971.     else if (lnum >= screen_Rows)    /* scrolled off of the screen */
  972.     clip_star.state = SELECT_CLEARED;
  973.     else
  974.     clip_star.start.lnum = lnum;
  975.  
  976.     lnum = clip_star.end.lnum - rows;
  977.     if (lnum < 0)            /* scrolled off of the screen */
  978.     clip_star.state = SELECT_CLEARED;
  979.     else if (lnum >= screen_Rows)
  980.     clip_star.end.lnum = screen_Rows - 1;
  981.     else
  982.     clip_star.end.lnum = lnum;
  983. }
  984.  
  985. /*
  986.  * Invert a region of the display between a starting and ending row and column
  987.  * Values for "how":
  988.  * CLIP_CLEAR:  undo inversion
  989.  * CLIP_SET:    set inversion
  990.  * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
  991.  * 0: invert (GUI only).
  992.  */
  993.     static void
  994. clip_invert_area(row1, col1, row2, col2, how)
  995.     int        row1;
  996.     int        col1;
  997.     int        row2;
  998.     int        col2;
  999.     int        how;
  1000. {
  1001.     int        invert = FALSE;
  1002.  
  1003.     if (how == CLIP_SET)
  1004.     invert = TRUE;
  1005.  
  1006.     /* Swap the from and to positions so the from is always before */
  1007.     if (clip_compare_pos(row1, col1, row2, col2) > 0)
  1008.     {
  1009.     int tmp_row, tmp_col;
  1010.  
  1011.     tmp_row = row1;
  1012.     tmp_col = col1;
  1013.     row1    = row2;
  1014.     col1    = col2;
  1015.     row2    = tmp_row;
  1016.     col2    = tmp_col;
  1017.     }
  1018.     else if (how == CLIP_TOGGLE)
  1019.     invert = TRUE;
  1020.  
  1021.     /* If all on the same line, do it the easy way */
  1022.     if (row1 == row2)
  1023.     {
  1024.     clip_invert_rectangle(row1, col1, 1, col2 - col1, invert);
  1025.     }
  1026.     else
  1027.     {
  1028.     /* Handle a piece of the first line */
  1029.     if (col1 > 0)
  1030.     {
  1031.         clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert);
  1032.         row1++;
  1033.     }
  1034.  
  1035.     /* Handle a piece of the last line */
  1036.     if (col2 < Columns - 1)
  1037.     {
  1038.         clip_invert_rectangle(row2, 0, 1, col2, invert);
  1039.         row2--;
  1040.     }
  1041.  
  1042.     /* Handle the rectangle thats left */
  1043.     if (row2 >= row1)
  1044.         clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns,
  1045.                                       invert);
  1046.     }
  1047. }
  1048.  
  1049. /*
  1050.  * Invert or un-invert a rectangle of the screen.
  1051.  * "invert" is true if the result is inverted.
  1052.  */
  1053.     static void
  1054. clip_invert_rectangle(row, col, height, width, invert)
  1055.     int        row;
  1056.     int        col;
  1057.     int        height;
  1058.     int        width;
  1059.     int        invert;
  1060. {
  1061. #ifdef FEAT_GUI
  1062.     if (gui.in_use)
  1063.     gui_mch_invert_rectangle(row, col, height, width);
  1064.     else
  1065. #endif
  1066.     screen_draw_rectangle(row, col, height, width, invert);
  1067. }
  1068.  
  1069. /*
  1070.  * Copy the currently selected area into the '*' register so it will be
  1071.  * available for pasting.
  1072.  * When "both" is TRUE also copy to the '+' register.
  1073.  */
  1074. /*ARGSUSED*/
  1075.     void
  1076. clip_copy_modeless_selection(both)
  1077.     int        both;
  1078. {
  1079.     char_u    *buffer;
  1080.     char_u    *bufp;
  1081.     int        row;
  1082.     int        start_col;
  1083.     int        end_col;
  1084.     int        line_end_col;
  1085.     int        add_newline_flag = FALSE;
  1086.     int        len;
  1087. #ifdef FEAT_MBYTE
  1088.     char_u    *p;
  1089.     int        i;
  1090. #endif
  1091.     int        row1 = clip_star.start.lnum;
  1092.     int        col1 = clip_star.start.col;
  1093.     int        row2 = clip_star.end.lnum;
  1094.     int        col2 = clip_star.end.col;
  1095.  
  1096.     /*
  1097.      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
  1098.      */
  1099.     if (row1 > row2)
  1100.     {
  1101.     row = row1; row1 = row2; row2 = row;
  1102.     row = col1; col1 = col2; col2 = row;
  1103.     }
  1104.     else if (row1 == row2 && col1 > col2)
  1105.     {
  1106.     row = col1; col1 = col2; col2 = row;
  1107.     }
  1108. #ifdef FEAT_MBYTE
  1109.     /* correct starting point for being on right halve of double-wide char */
  1110.     p = ScreenLines + LineOffset[row1];
  1111.     if (enc_dbcs != 0)
  1112.     col1 -= (*mb_head_off)(p, p + col1);
  1113.     else if (enc_utf8 && p[col1] == 0)
  1114.     --col1;
  1115. #endif
  1116.  
  1117.     /* Create a temporary buffer for storing the text */
  1118.     len = (row2 - row1 + 1) * Columns + 1;
  1119. #ifdef FEAT_MBYTE
  1120.     if (enc_dbcs != 0)
  1121.     len *= 2;    /* max. 2 bytes per display cell */
  1122.     else if (enc_utf8)
  1123.     len *= 9;    /* max. 3 bytes per display cell + 2 composing chars */
  1124. #endif
  1125.     buffer = lalloc((long_u)len, TRUE);
  1126.     if (buffer == NULL)        /* out of memory */
  1127.     return;
  1128.  
  1129.     /* Process each row in the selection */
  1130.     for (bufp = buffer, row = row1; row <= row2; row++)
  1131.     {
  1132.     if (row == row1)
  1133.         start_col = col1;
  1134.     else
  1135.         start_col = 0;
  1136.  
  1137.     if (row == row2)
  1138.         end_col = col2;
  1139.     else
  1140.         end_col = Columns;
  1141.  
  1142.     line_end_col = clip_get_line_end(row);
  1143.  
  1144.     /* See if we need to nuke some trailing whitespace */
  1145.     if (end_col >= Columns && (row < row2 || end_col > line_end_col))
  1146.     {
  1147.         /* Get rid of trailing whitespace */
  1148.         end_col = line_end_col;
  1149.         if (end_col < start_col)
  1150.         end_col = start_col;
  1151.  
  1152.         /* If the last line extended to the end, add an extra newline */
  1153.         if (row == row2)
  1154.         add_newline_flag = TRUE;
  1155.     }
  1156.  
  1157.     /* If after the first row, we need to always add a newline */
  1158.     if (row > row1)
  1159.         *bufp++ = NL;
  1160.  
  1161.     if (row < screen_Rows && end_col <= screen_Columns)
  1162.     {
  1163. #ifdef FEAT_MBYTE
  1164.         if (enc_dbcs != 0)
  1165.         {
  1166.         p = ScreenLines + LineOffset[row];
  1167.         for (i = start_col; i < end_col; ++i)
  1168.             if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
  1169.             {
  1170.             /* single-width double-byte char */
  1171.             *bufp++ = 0x8e;
  1172.             *bufp++ = ScreenLines2[LineOffset[row] + i];
  1173.             }
  1174.             else
  1175.             {
  1176.             *bufp++ = p[i];
  1177.             if (MB_BYTE2LEN(p[i]) == 2)
  1178.                 *bufp++ = p[++i];
  1179.             }
  1180.         }
  1181.         else if (enc_utf8)
  1182.         {
  1183.         int    off;
  1184.  
  1185.         off = LineOffset[row];
  1186.         for (i = start_col; i < end_col; ++i)
  1187.         {
  1188.             /* The base character is either in ScreenLinesUC[] or
  1189.              * ScreenLines[]. */
  1190.             if (ScreenLinesUC[off + i] == 0)
  1191.             *bufp++ = ScreenLines[off + i];
  1192.             else
  1193.             {
  1194.             bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
  1195.             if (ScreenLinesC1[off + i] != 0)
  1196.             {
  1197.                 /* Add one or two composing characters. */
  1198.                 bufp += utf_char2bytes(ScreenLinesC1[off + i],
  1199.                                     bufp);
  1200.                 if (ScreenLinesC2[off + i] != 0)
  1201.                 bufp += utf_char2bytes(ScreenLinesC2[off + i],
  1202.                     bufp);
  1203.             }
  1204.             }
  1205.             /* Skip right halve of double-wide character. */
  1206.             if (ScreenLines[off + i + 1] == 0)
  1207.             ++i;
  1208.         }
  1209.         }
  1210.         else
  1211. #endif
  1212.         {
  1213.         STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
  1214.                              end_col - start_col);
  1215.         bufp += end_col - start_col;
  1216.         }
  1217.     }
  1218.     }
  1219.  
  1220.     /* Add a newline at the end if the selection ended there */
  1221.     if (add_newline_flag)
  1222.     *bufp++ = NL;
  1223.  
  1224.     /* First cleanup any old selection and become the owner. */
  1225.     clip_free_selection(&clip_star);
  1226.     clip_own_selection(&clip_star);
  1227.  
  1228.     /* Yank the text into the '*' register. */
  1229.     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
  1230.  
  1231.     /* Make the register contents available to the outside world. */
  1232.     clip_gen_set_selection(&clip_star);
  1233.  
  1234. #ifdef FEAT_X11
  1235.     if (both)
  1236.     {
  1237.     /* Do the same for the '+' register. */
  1238.     clip_free_selection(&clip_plus);
  1239.     clip_own_selection(&clip_plus);
  1240.     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
  1241.     clip_gen_set_selection(&clip_plus);
  1242.     }
  1243. #endif
  1244.     vim_free(buffer);
  1245. }
  1246.  
  1247. /*
  1248.  * Find the starting and ending positions of the word at the given row and
  1249.  * column.  Only white-separated words are recognized here.
  1250.  */
  1251. #define CHAR_CLASS(c)    (c <= ' ' ? ' ' : vim_iswordc(c))
  1252.  
  1253.     static void
  1254. clip_get_word_boundaries(cb, row, col)
  1255.     VimClipboard    *cb;
  1256.     int            row;
  1257.     int            col;
  1258. {
  1259.     int        start_class;
  1260.     int        temp_col;
  1261.     char_u    *p;
  1262. #ifdef FEAT_MBYTE
  1263.     int        mboff;
  1264. #endif
  1265.  
  1266.     if (row >= screen_Rows || col >= screen_Columns)
  1267.     return;
  1268.  
  1269.     p = ScreenLines + LineOffset[row];
  1270. #ifdef FEAT_MBYTE
  1271.     /* Correct for starting in the right halve of a double-wide char */
  1272.     if (enc_dbcs != 0)
  1273.     col -= dbcs_screen_head_off(p, p + col);
  1274.     else if (enc_utf8 && p[col] == 0)
  1275.     --col;
  1276. #endif
  1277.     start_class = CHAR_CLASS(p[col]);
  1278.  
  1279.     temp_col = col;
  1280.     for ( ; temp_col > 0; temp_col--)
  1281. #ifdef FEAT_MBYTE
  1282.     if (enc_dbcs != 0
  1283.            && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
  1284.         temp_col -= mboff;
  1285.     else
  1286. #endif
  1287.     if (CHAR_CLASS(p[temp_col - 1]) != start_class
  1288. #ifdef FEAT_MBYTE
  1289.         && !(enc_utf8 && p[temp_col - 1] == 0)
  1290. #endif
  1291.         )
  1292.         break;
  1293.     cb->word_start_col = temp_col;
  1294.  
  1295.     temp_col = col;
  1296.     for ( ; temp_col < screen_Columns; temp_col++)
  1297. #ifdef FEAT_MBYTE
  1298.     if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
  1299.         ++temp_col;
  1300.     else
  1301. #endif
  1302.     if (CHAR_CLASS(p[temp_col]) != start_class
  1303. #ifdef FEAT_MBYTE
  1304.         && !(enc_utf8 && p[temp_col] == 0)
  1305. #endif
  1306.         )
  1307.         break;
  1308.     cb->word_end_col = temp_col;
  1309. }
  1310.  
  1311. /*
  1312.  * Find the column position for the last non-whitespace character on the given
  1313.  * line.
  1314.  */
  1315.     static int
  1316. clip_get_line_end(row)
  1317.     int        row;
  1318. {
  1319.     int        i;
  1320.  
  1321.     if (row >= screen_Rows)
  1322.     return 0;
  1323.     for (i = screen_Columns; i > 0; i--)
  1324.     if (ScreenLines[LineOffset[row] + i - 1] != ' ')
  1325.         break;
  1326.     return i;
  1327. }
  1328.  
  1329. /*
  1330.  * Update the currently selected region by adding and/or subtracting from the
  1331.  * beginning or end and inverting the changed area(s).
  1332.  */
  1333.     static void
  1334. clip_update_modeless_selection(cb, row1, col1, row2, col2)
  1335.     VimClipboard    *cb;
  1336.     int            row1;
  1337.     int            col1;
  1338.     int            row2;
  1339.     int            col2;
  1340. {
  1341.     /* See if we changed at the beginning of the selection */
  1342.     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
  1343.     {
  1344.     clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col,
  1345.                                  CLIP_TOGGLE);
  1346.     cb->start.lnum = row1;
  1347.     cb->start.col  = col1;
  1348.     }
  1349.  
  1350.     /* See if we changed at the end of the selection */
  1351.     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
  1352.     {
  1353.     clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2,
  1354.                                  CLIP_TOGGLE);
  1355.     cb->end.lnum = row2;
  1356.     cb->end.col  = col2;
  1357.     }
  1358. }
  1359.  
  1360.     int
  1361. clip_gen_own_selection(cbd)
  1362.     VimClipboard    *cbd;
  1363. {
  1364. #ifdef FEAT_XCLIPBOARD
  1365. # ifdef FEAT_GUI
  1366.     if (gui.in_use)
  1367.     return clip_mch_own_selection(cbd);
  1368.     else
  1369. # endif
  1370.     return clip_xterm_own_selection(cbd);
  1371. #else
  1372.     return clip_mch_own_selection(cbd);
  1373. #endif
  1374. }
  1375.  
  1376.     void
  1377. clip_gen_lose_selection(cbd)
  1378.     VimClipboard    *cbd;
  1379. {
  1380. #ifdef FEAT_XCLIPBOARD
  1381. # ifdef FEAT_GUI
  1382.     if (gui.in_use)
  1383.     clip_mch_lose_selection(cbd);
  1384.     else
  1385. # endif
  1386.     clip_xterm_lose_selection(cbd);
  1387. #else
  1388.     clip_mch_lose_selection(cbd);
  1389. #endif
  1390. }
  1391.  
  1392.     void
  1393. clip_gen_set_selection(cbd)
  1394.     VimClipboard    *cbd;
  1395. {
  1396. #ifdef FEAT_XCLIPBOARD
  1397. # ifdef FEAT_GUI
  1398.     if (gui.in_use)
  1399.     clip_mch_set_selection(cbd);
  1400.     else
  1401. # endif
  1402.     clip_xterm_set_selection(cbd);
  1403. #else
  1404.     clip_mch_set_selection(cbd);
  1405. #endif
  1406. }
  1407.  
  1408.     void
  1409. clip_gen_request_selection(cbd)
  1410.     VimClipboard    *cbd;
  1411. {
  1412. #ifdef FEAT_XCLIPBOARD
  1413. # ifdef FEAT_GUI
  1414.     if (gui.in_use)
  1415.     clip_mch_request_selection(cbd);
  1416.     else
  1417. # endif
  1418.     clip_xterm_request_selection(cbd);
  1419. #else
  1420.     clip_mch_request_selection(cbd);
  1421. #endif
  1422. }
  1423.  
  1424. #endif /* FEAT_CLIPBOARD */
  1425.  
  1426. /*****************************************************************************
  1427.  * Functions that handle the input buffer.
  1428.  * This is used for any GUI version, and the unix terminal version.
  1429.  *
  1430.  * For Unix, the input characters are buffered to be able to check for a
  1431.  * CTRL-C.  This should be done with signals, but I don't know how to do that
  1432.  * in a portable way for a tty in RAW mode.
  1433.  *
  1434.  * For the client-server code in the console the received keys are put in the
  1435.  * input buffer.
  1436.  */
  1437.  
  1438. #if defined(UNIX) || defined(FEAT_GUI) || defined(OS2) || defined(VMS) \
  1439.     || defined(FEAT_CLIENTSERVER) || defined(PROTO)
  1440.  
  1441. /*
  1442.  * Internal typeahead buffer.  Includes extra space for long key code
  1443.  * descriptions which would otherwise overflow.  The buffer is considered full
  1444.  * when only this extra space (or part of it) remains.
  1445.  */
  1446. #ifdef VMS
  1447. # define INBUFLEN 10000 /* for proper cut/paste between X windows in ch. mode */
  1448. #else
  1449. # if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_CLIENTSERVER)
  1450.    /*
  1451.     * Sun WorkShop stuffs debugger commands into the input buffer. This requires
  1452.     * a larger buffer...
  1453.     * (Madsen) Go with this for remote input as well ...
  1454.     */
  1455. #  define INBUFLEN 4096
  1456. # else
  1457. #  define INBUFLEN 250
  1458. # endif
  1459. #endif
  1460.  
  1461. static char_u    inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
  1462. static int    inbufcount = 0;        /* number of chars in inbuf[] */
  1463.  
  1464. /*
  1465.  * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
  1466.  * trash_input_buf() are functions for manipulating the input buffer.  These
  1467.  * are used by the gui_* calls when a GUI is used to handle keyboard input.
  1468.  */
  1469.  
  1470.     int
  1471. vim_is_input_buf_full()
  1472. {
  1473.     return (inbufcount >= INBUFLEN);
  1474. }
  1475.  
  1476.     int
  1477. vim_is_input_buf_empty()
  1478. {
  1479.     return (inbufcount == 0);
  1480. }
  1481.  
  1482. #if defined(FEAT_OLE) || defined(PROTO)
  1483.     int
  1484. vim_free_in_input_buf()
  1485. {
  1486.     return (INBUFLEN - inbufcount);
  1487. }
  1488. #endif
  1489.  
  1490. #if defined(FEAT_GUI_GTK) || defined(PROTO)
  1491.     int
  1492. vim_used_in_input_buf()
  1493. {
  1494.     return inbufcount;
  1495. }
  1496. #endif
  1497.  
  1498. #if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM) \
  1499.     || defined(FEAT_XCLIPBOARD) || defined(VMS) \
  1500.     || defined(FEAT_SNIFF) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
  1501. /*
  1502.  * Add the given bytes to the input buffer
  1503.  * Special keys start with CSI.  A real CSI must have been translated to
  1504.  * CSI KS_EXTRA KE_CSI.  K_SPECIAL doesn't require translation.
  1505.  */
  1506.     void
  1507. add_to_input_buf(s, len)
  1508.     char_u  *s;
  1509.     int        len;
  1510. {
  1511.     if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
  1512.     return;        /* Shouldn't ever happen! */
  1513.  
  1514. #ifdef FEAT_HANGULIN
  1515.     if ((State & (INSERT|CMDLINE)) && hangul_input_state_get())
  1516.     if ((len = hangul_input_process(s, len)) == 0)
  1517.         return;
  1518. #endif
  1519.  
  1520.     while (len--)
  1521.     inbuf[inbufcount++] = *s++;
  1522. }
  1523. #endif
  1524.  
  1525. #if defined(FEAT_HANGULIN) || defined(PROTO)
  1526.     void
  1527. push_raw_key (s, len)
  1528.     char_u  *s;
  1529.     int        len;
  1530. {
  1531.     while (len--)
  1532.     inbuf[inbufcount++] = *s++;
  1533. }
  1534. #endif
  1535.  
  1536. #if defined(FEAT_GUI) || defined(PROTO)
  1537. /* Remove everything from the input buffer.  Called when ^C is found */
  1538.     void
  1539. trash_input_buf()
  1540. {
  1541.     inbufcount = 0;
  1542. }
  1543. #endif
  1544.  
  1545. /*
  1546.  * Read as much data from the input buffer as possible up to maxlen, and store
  1547.  * it in buf.
  1548.  * Note: this function used to be Read() in unix.c
  1549.  */
  1550.     int
  1551. read_from_input_buf(buf, maxlen)
  1552.     char_u  *buf;
  1553.     long    maxlen;
  1554. {
  1555.     if (inbufcount == 0)    /* if the buffer is empty, fill it */
  1556.     fill_input_buf(TRUE);
  1557.     if (maxlen > inbufcount)
  1558.     maxlen = inbufcount;
  1559.     mch_memmove(buf, inbuf, (size_t)maxlen);
  1560.     inbufcount -= maxlen;
  1561.     if (inbufcount)
  1562.     mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
  1563.     return (int)maxlen;
  1564. }
  1565.  
  1566.     void
  1567. fill_input_buf(exit_on_error)
  1568.     int    exit_on_error;
  1569. {
  1570. #if defined(UNIX) || defined(OS2) || defined(VMS)
  1571.     int        len;
  1572.     int        try;
  1573.     static int    did_read_something = FALSE;
  1574. #endif
  1575. #ifdef VMS
  1576.     extern char ibuf[];
  1577. #endif
  1578.  
  1579. #ifdef FEAT_GUI
  1580.     if (gui.in_use)
  1581.     {
  1582.     gui_mch_update();
  1583.     return;
  1584.     }
  1585. #endif
  1586. #if defined(UNIX) || defined(OS2) || defined(VMS)
  1587.     if (vim_is_input_buf_full())
  1588.     return;
  1589.     /*
  1590.      * Fill_input_buf() is only called when we really need a character.
  1591.      * If we can't get any, but there is some in the buffer, just return.
  1592.      * If we can't get any, and there isn't any in the buffer, we give up and
  1593.      * exit Vim.
  1594.      */
  1595. # ifdef __BEOS__
  1596.     /*
  1597.      * On the BeBox version (for now), all input is secretly performed within
  1598.      * beos_select() which is called from RealWaitForChar().
  1599.      */
  1600.     while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0, NULL))
  1601.         ;
  1602.     len = inbufcount;
  1603.     inbufcount = 0;
  1604. # else
  1605.  
  1606. #  ifdef FEAT_SNIFF
  1607.     if (sniff_request_waiting)
  1608.     {
  1609.     add_to_input_buf((char_u *)"\233sniff",6); /* results in K_SNIFF */
  1610.     sniff_request_waiting = 0;
  1611.     want_sniff_request = 0;
  1612.     return;
  1613.     }
  1614. #  endif
  1615. #  ifdef VMS_OLD_STUFF
  1616.     while (!vim_is_input_buf_full() && RealWaitForChar(0, 0L))
  1617.     {
  1618.     add_to_input_buf((char_u *)ibuf, 1);
  1619.     }
  1620.     if (inbufcount < 1 && !exit_on_error)
  1621.     return;
  1622.     len = inbufcount;
  1623.     inbufcount = 0;
  1624. #  else
  1625.  
  1626.     len = 0;    /* to avoid gcc warning */
  1627.     for (try = 0; try < 100; ++try)
  1628.     {
  1629.     len = read(read_cmd_fd, (char *)inbuf + inbufcount,
  1630.         (size_t)((INBUFLEN - inbufcount)
  1631. #  ifdef FEAT_MBYTE
  1632.         / input_conv.vc_factor
  1633. #  endif
  1634.         ));
  1635.     if (len > 0 || got_int)
  1636.         break;
  1637.     /*
  1638.      * If reading stdin results in an error, continue reading stderr.
  1639.      * This helps when using "foo | xargs vim".
  1640.      */
  1641.     if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
  1642.     {
  1643.         int m = cur_tmode;
  1644.  
  1645.         /* We probably set the wrong file descriptor to raw mode.  Switch
  1646.          * back to cooked mode, use another descriptor and set the mode to
  1647.          * what it was. */
  1648.         settmode(TMODE_COOK);
  1649. #ifdef HAVE_DUP
  1650.         /* Use stderr for stdin, also works for shell commands. */
  1651.         close(0);
  1652.         dup(2);
  1653. #else
  1654.         read_cmd_fd = 2;    /* read from stderr instead of stdin */
  1655. #endif
  1656.         settmode(m);
  1657.     }
  1658.     if (!exit_on_error)
  1659.         return;
  1660.     }
  1661. #  endif /* VMS */
  1662. # endif
  1663.     if (len <= 0 && !got_int)
  1664.     read_error_exit();
  1665.     did_read_something = TRUE;
  1666.     if (got_int)
  1667.     {
  1668.     inbuf[inbufcount] = 3;
  1669.     inbufcount = 1;
  1670.     }
  1671.     else
  1672.     {
  1673. # ifdef FEAT_MBYTE
  1674.     /* May perform conversion on the input characters. */
  1675.     if (input_conv.vc_type != CONV_NONE)
  1676.         len = convert_input(inbuf + inbufcount, len, INBUFLEN - inbufcount);
  1677. # endif
  1678.     while (len-- > 0)
  1679.     {
  1680.         /*
  1681.          * if a CTRL-C was typed, remove it from the buffer and set got_int
  1682.          */
  1683.         if (inbuf[inbufcount] == 3 && ctrl_c_interrupts)
  1684.         {
  1685.         /* remove everything typed before the CTRL-C */
  1686.         mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
  1687.         inbufcount = 0;
  1688.         got_int = TRUE;
  1689.         }
  1690.         ++inbufcount;
  1691.     }
  1692.     }
  1693. #endif /* UNIX or OS2 or VMS*/
  1694. }
  1695. #endif /* defined(UNIX) || defined(FEAT_GUI) || defined(OS2)  || defined(VMS) */
  1696.  
  1697. /*
  1698.  * Exit because of an input read error.
  1699.  */
  1700.     void
  1701. read_error_exit()
  1702. {
  1703.     if (silent_mode)    /* Normal way to exit for "ex -s" */
  1704.     getout(0);
  1705.     STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
  1706.     preserve_exit();
  1707. }
  1708.  
  1709. #if defined(CURSOR_SHAPE) || defined(PROTO)
  1710. /*
  1711.  * May update the shape of the cursor.
  1712.  */
  1713.     void
  1714. ui_cursor_shape()
  1715. {
  1716. # ifdef FEAT_GUI
  1717.     if (gui.in_use)
  1718.     gui_update_cursor_later();
  1719. # endif
  1720. # ifdef MCH_CURSOR_SHAPE
  1721.     mch_update_cursor();
  1722. # endif
  1723. }
  1724. #endif
  1725.  
  1726. #if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(PROTO)
  1727. /*
  1728.  * Check bounds for column number
  1729.  */
  1730.     int
  1731. check_col(col)
  1732.     int        col;
  1733. {
  1734.     if (col < 0)
  1735.     return 0;
  1736.     if (col >= (int)screen_Columns)
  1737.     return (int)screen_Columns - 1;
  1738.     return col;
  1739. }
  1740.  
  1741. /*
  1742.  * Check bounds for row number
  1743.  */
  1744.     int
  1745. check_row(row)
  1746.     int        row;
  1747. {
  1748.     if (row < 0)
  1749.     return 0;
  1750.     if (row >= (int)screen_Rows)
  1751.     return (int)screen_Rows - 1;
  1752.     return row;
  1753. }
  1754. #endif
  1755.  
  1756. /*
  1757.  * Stuff for the X clipboard.  Shared between VMS and Unix.
  1758.  */
  1759.  
  1760. #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO)
  1761. # include <X11/Xatom.h>
  1762. # include <X11/Intrinsic.h>
  1763.  
  1764. /*
  1765.  * Open the application context (if it hasn't been opened yet).
  1766.  * Used for Motif and Athena GUI and the xterm clipboard.
  1767.  */
  1768.     void
  1769. open_app_context()
  1770. {
  1771.     if (app_context == NULL)
  1772.     {
  1773.     XtToolkitInitialize();
  1774.     app_context = XtCreateApplicationContext();
  1775.     }
  1776. }
  1777.  
  1778. static Atom    vim_atom;    /* Vim's own special selection format */
  1779. static Atom    compound_text_atom;
  1780. static Atom    text_atom;
  1781. static Atom    targets_atom;
  1782.  
  1783.     void
  1784. x11_setup_atoms(dpy)
  1785.     Display    *dpy;
  1786. {
  1787.     vim_atom           = XInternAtom(dpy, VIM_ATOM_NAME,   False);
  1788.     compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False);
  1789.     text_atom           = XInternAtom(dpy, "TEXT",       False);
  1790.     targets_atom       = XInternAtom(dpy, "TARGETS",       False);
  1791.     clip_star.sel_atom = XA_PRIMARY;
  1792.     clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD",     False);
  1793. }
  1794.  
  1795. /*
  1796.  * X Selection stuff, for cutting and pasting text to other windows.
  1797.  */
  1798.  
  1799. static void  clip_x11_request_selection_cb __ARGS((Widget, XtPointer, Atom *, Atom *, XtPointer, long_u *, int *));
  1800.  
  1801. /* ARGSUSED */
  1802.     static void
  1803. clip_x11_request_selection_cb(w, success, sel_atom, type, value, length,
  1804.                   format)
  1805.     Widget    w;
  1806.     XtPointer    success;
  1807.     Atom    *sel_atom;
  1808.     Atom    *type;
  1809.     XtPointer    value;
  1810.     long_u    *length;
  1811.     int        *format;
  1812. {
  1813.     int        motion_type;
  1814.     long_u    len;
  1815.     char_u    *p;
  1816.     char    **text_list = NULL;
  1817.     VimClipboard    *cbd;
  1818.  
  1819.     if (*sel_atom == clip_plus.sel_atom)
  1820.     cbd = &clip_plus;
  1821.     else
  1822.     cbd = &clip_star;
  1823.  
  1824.     if (value == NULL || *length == 0)
  1825.     {
  1826.     clip_free_selection(cbd);    /* ???  [what's the query?] */
  1827.     *(int *)success = FALSE;
  1828.     return;
  1829.     }
  1830.     motion_type = MCHAR;
  1831.     p = (char_u *)value;
  1832.     len = *length;
  1833.     if (*type == vim_atom)
  1834.     {
  1835.     motion_type = *p++;
  1836.     len--;
  1837.     }
  1838.     else if (*type == compound_text_atom || (
  1839. #ifdef FEAT_MBYTE
  1840.         enc_dbcs != 0 &&
  1841. #endif
  1842.         *type == text_atom))
  1843.     {
  1844.     XTextProperty    text_prop;
  1845.     int        n_text = 0;
  1846.     int        status;
  1847.  
  1848.     text_prop.value = (unsigned char *)value;
  1849.     text_prop.encoding = *type;
  1850.     text_prop.format = *format;
  1851.     text_prop.nitems = STRLEN(value);
  1852.     status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop,
  1853.                              &text_list, &n_text);
  1854.     if (status != Success || n_text < 1)
  1855.     {
  1856.         *(int *)success = FALSE;
  1857.         return;
  1858.     }
  1859.     p = (char_u *)text_list[0];
  1860.     len = STRLEN(p);
  1861.     }
  1862.     clip_yank_selection(motion_type, p, (long)len, cbd);
  1863.  
  1864.     if (text_list != NULL)
  1865.     XFreeStringList(text_list);
  1866.  
  1867.     XtFree((char *)value);
  1868.     *(int *)success = TRUE;
  1869. }
  1870.  
  1871.     void
  1872. clip_x11_request_selection(myShell, dpy, cbd)
  1873.     Widget    myShell;
  1874.     Display    *dpy;
  1875.     VimClipboard    *cbd;
  1876. {
  1877.     XEvent    event;
  1878.     Atom    type;
  1879.     static int    success;
  1880.     int        i;
  1881.     int        nbytes = 0;
  1882.     char_u    *buffer;
  1883.  
  1884.     for (i = 0; i < 4; i++)
  1885.     {
  1886.     switch (i)
  1887.     {
  1888.         case 0:  type = vim_atom;    break;
  1889.         case 1:  type = compound_text_atom; break;
  1890.         case 2:  type = text_atom;    break;
  1891.         default: type = XA_STRING;
  1892.     }
  1893.     XtGetSelectionValue(myShell, cbd->sel_atom, type,
  1894.         clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
  1895.  
  1896.     /* Make sure the request for the selection goes out before waiting for
  1897.      * a response. */
  1898.     XFlush(dpy);
  1899.  
  1900.     /*
  1901.      * Wait for result of selection request, otherwise if we type more
  1902.      * characters, then they will appear before the one that requested the
  1903.      * paste!  Don't worry, we will catch up with any other events later.
  1904.      */
  1905.     for (;;)
  1906.     {
  1907.         if (XCheckTypedEvent(dpy, SelectionNotify, &event))
  1908.         break;
  1909.  
  1910.         /* Do we need this?  Probably not. */
  1911.         XSync(dpy, False);
  1912.     }
  1913.  
  1914.     /* this is where clip_x11_request_selection_cb() is actually called */
  1915.     XtDispatchEvent(&event);
  1916.  
  1917.     if (success)
  1918.         return;
  1919.     }
  1920.  
  1921.     /* Final fallback position - use the X CUT_BUFFER0 store */
  1922.     buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0);
  1923.     if (nbytes > 0)
  1924.     {
  1925.     /* Got something */
  1926.     clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
  1927.     XFree((void *)buffer);
  1928.     if (p_verbose > 0)
  1929.         smsg((char_u *)_("Used CUT_BUFFER0 instead of empty selection") );
  1930.     }
  1931. }
  1932.  
  1933. static Boolean    clip_x11_convert_selection_cb __ARGS((Widget, Atom *, Atom *, Atom *, XtPointer *, long_u *, int *));
  1934.  
  1935. /* ARGSUSED */
  1936.     static Boolean
  1937. clip_x11_convert_selection_cb(w, sel_atom, target, type, value, length, format)
  1938.     Widget    w;
  1939.     Atom    *sel_atom;
  1940.     Atom    *target;
  1941.     Atom    *type;
  1942.     XtPointer    *value;
  1943.     long_u    *length;
  1944.     int        *format;
  1945. {
  1946.     char_u    *string;
  1947.     char_u    *result;
  1948.     int        motion_type;
  1949.     VimClipboard    *cbd;
  1950.  
  1951.     if (*sel_atom == clip_plus.sel_atom)
  1952.     cbd = &clip_plus;
  1953.     else
  1954.     cbd = &clip_star;
  1955.  
  1956.     if (!cbd->owned)
  1957.     return False;        /* Shouldn't ever happen */
  1958.  
  1959.     /* requestor wants to know what target types we support */
  1960.     if (*target == targets_atom)
  1961.     {
  1962.     Atom *array;
  1963.  
  1964.     if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 5))) == NULL)
  1965.         return False;
  1966.     *value = (XtPointer)array;
  1967.     array[0] = XA_STRING;
  1968.     array[1] = targets_atom;
  1969.     array[2] = vim_atom;
  1970.     array[3] = text_atom;
  1971.     array[4] = compound_text_atom;
  1972.     *type = XA_ATOM;
  1973.     *format = sizeof(Atom) * 8;
  1974.     *length = 5;
  1975.     return True;
  1976.     }
  1977.  
  1978.     if (       *target != XA_STRING
  1979.         && *target != vim_atom
  1980.         && *target != text_atom
  1981.         && *target != compound_text_atom)
  1982.     return False;
  1983.  
  1984.     clip_get_selection(cbd);
  1985.     motion_type = clip_convert_selection(&string, length, cbd);
  1986.     if (motion_type < 0)
  1987.     return False;
  1988.  
  1989.     /* For our own format, the first byte contains the motion type */
  1990.     if (*target == vim_atom)
  1991.     (*length)++;
  1992.  
  1993.     *value = XtMalloc((Cardinal)*length);
  1994.     result = (char_u *)*value;
  1995.     if (result == NULL)
  1996.     {
  1997.     vim_free(string);
  1998.     return False;
  1999.     }
  2000.  
  2001.     if (*target == XA_STRING)
  2002.     {
  2003.     mch_memmove(result, string, (size_t)(*length));
  2004.     *type = XA_STRING;
  2005.     }
  2006.     else if (*target == compound_text_atom
  2007.         || *target == text_atom)
  2008.     {
  2009.     XTextProperty    text_prop;
  2010.     char        *string_nt = (char *)alloc((unsigned)*length + 1);
  2011.  
  2012.     /* create NUL terminated string which XmbTextListToTextProperty wants */
  2013.     mch_memmove(string_nt, string, (size_t)*length);
  2014.     string_nt[*length] = NUL;
  2015.     XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt, 1,
  2016.                           XCompoundTextStyle, &text_prop);
  2017.     vim_free(string_nt);
  2018.     XtFree(*value);            /* replace with COMPOUND text */
  2019.     *value = (XtPointer)(text_prop.value);    /*    from plain text */
  2020.     *length = text_prop.nitems;
  2021.     *type = compound_text_atom;
  2022.     }
  2023.     else
  2024.     {
  2025.     result[0] = motion_type;
  2026.     mch_memmove(result + 1, string, (size_t)(*length - 1));
  2027.     *type = vim_atom;
  2028.     }
  2029.     *format = 8;        /* 8 bits per char */
  2030.     vim_free(string);
  2031.     return True;
  2032. }
  2033.  
  2034. static void  clip_x11_lose_ownership_cb __ARGS((Widget, Atom *));
  2035.  
  2036. /* ARGSUSED */
  2037.     static void
  2038. clip_x11_lose_ownership_cb(w, sel_atom)
  2039.     Widget  w;
  2040.     Atom    *sel_atom;
  2041. {
  2042.     if (*sel_atom == clip_plus.sel_atom)
  2043.     clip_lose_selection(&clip_plus);
  2044.     else
  2045.     clip_lose_selection(&clip_star);
  2046. }
  2047.  
  2048.     void
  2049. clip_x11_lose_selection(myShell, cbd)
  2050.     Widget    myShell;
  2051.     VimClipboard    *cbd;
  2052. {
  2053.     XtDisownSelection(myShell, cbd->sel_atom, CurrentTime);
  2054. }
  2055.  
  2056.     int
  2057. clip_x11_own_selection(myShell, cbd)
  2058.     Widget    myShell;
  2059.     VimClipboard    *cbd;
  2060. {
  2061.     if (XtOwnSelection(myShell, cbd->sel_atom, CurrentTime,
  2062.         clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
  2063.                                    NULL) == False)
  2064.     return FAIL;
  2065.     return OK;
  2066. }
  2067.  
  2068. /*
  2069.  * Send the current selection to the clipboard.  Do nothing for X because we
  2070.  * will fill in the selection only when requested by another app.
  2071.  */
  2072. /*ARGSUSED*/
  2073.     void
  2074. clip_x11_set_selection(cbd)
  2075.     VimClipboard *cbd;
  2076. {
  2077. }
  2078. #endif
  2079.  
  2080. #if defined(FEAT_MOUSE) || defined(PROTO)
  2081.  
  2082. /*
  2083.  * Move the cursor to the specified row and column on the screen.
  2084.  * Change current window if neccesary.    Returns an integer with the
  2085.  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
  2086.  *
  2087.  * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
  2088.  * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
  2089.  *
  2090.  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
  2091.  * if the mouse is outside the window then the text will scroll, or if the
  2092.  * mouse was previously on a status line, then the status line may be dragged.
  2093.  *
  2094.  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
  2095.  * cursor is moved unless the cursor was on a status line.
  2096.  * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
  2097.  * IN_SEP_LINE depending on where the cursor was clicked.
  2098.  *
  2099.  * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
  2100.  * the mouse is on the status line of the same window.
  2101.  *
  2102.  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
  2103.  * the last call.
  2104.  *
  2105.  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
  2106.  * remembered.
  2107.  */
  2108.     int
  2109. jump_to_mouse(flags, inclusive, which_button)
  2110.     int        flags;
  2111.     int        *inclusive;    /* used for inclusive operator, can be NULL */
  2112.     int        which_button;    /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */
  2113. {
  2114.     static int    on_status_line = 0;    /* #lines below bottom of window */
  2115. #ifdef FEAT_VERTSPLIT
  2116.     static int    on_sep_line = 0;    /* on separator right of window */
  2117. #endif
  2118.     static int    prev_row = -1;
  2119.     static int    prev_col = -1;
  2120.  
  2121.     win_T    *wp, *old_curwin;
  2122.     pos_T    old_cursor;
  2123.     int        count;
  2124.     int        first;
  2125.     int        row = mouse_row;
  2126.     int        col = mouse_col;
  2127. #ifdef FEAT_FOLDING
  2128.     int        mouse_char;
  2129. #endif
  2130.  
  2131.     mouse_past_bottom = FALSE;
  2132.     mouse_past_eol = FALSE;
  2133.  
  2134.     if ((flags & MOUSE_DID_MOVE)
  2135.         && prev_row == mouse_row
  2136.         && prev_col == mouse_col)
  2137.     {
  2138. retnomove:
  2139.     /* before moving the cursor for a left click wich is NOT in a status
  2140.      * line, stop Visual mode */
  2141.     if (on_status_line)
  2142.         return IN_STATUS_LINE;
  2143. #ifdef FEAT_VERTSPLIT
  2144.     if (on_sep_line)
  2145.         return IN_SEP_LINE;
  2146. #endif
  2147. #ifdef FEAT_VISUAL
  2148.     if (flags & MOUSE_MAY_STOP_VIS)
  2149.     {
  2150.         end_visual_mode();
  2151.         redraw_curbuf_later(INVERTED);    /* delete the inversion */
  2152.     }
  2153. #endif
  2154. #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
  2155.     /* Continue a modeless selection in another window. */
  2156.     if (cmdwin_type != 0 && row < W_WINROW(curwin))
  2157.         return IN_OTHER_WIN;
  2158. #endif
  2159.     return IN_BUFFER;
  2160.     }
  2161.  
  2162.     prev_row = mouse_row;
  2163.     prev_col = mouse_col;
  2164.  
  2165.     if (flags & MOUSE_SETPOS)
  2166.     goto retnomove;                /* ugly goto... */
  2167.  
  2168. #ifdef FEAT_FOLDING
  2169.     /* Remember the character under the mouse, it might be a '-' or '+' in the
  2170.      * fold column. */
  2171.     if (row >= 0 && row < Rows && col >= 0 && col <= Columns)
  2172.     mouse_char = ScreenLines[LineOffset[row] + col];
  2173.     else
  2174.     mouse_char = ' ';
  2175. #endif
  2176.  
  2177.     old_curwin = curwin;
  2178.     old_cursor = curwin->w_cursor;
  2179.  
  2180.     if (!(flags & MOUSE_FOCUS))
  2181.     {
  2182.     if (row < 0 || col < 0)            /* check if it makes sense */
  2183.         return IN_UNKNOWN;
  2184.  
  2185. #ifdef FEAT_WINDOWS
  2186.     /* find the window where the row is in */
  2187.     wp = mouse_find_win(&row, &col);
  2188. #else
  2189.     wp = firstwin;
  2190. #endif
  2191.     /*
  2192.      * winpos and height may change in win_enter()!
  2193.      */
  2194.     if (row >= wp->w_height)        /* In (or below) status line */
  2195.         on_status_line = row - wp->w_height + 1;
  2196.     else
  2197.         on_status_line = 0;
  2198. #ifdef FEAT_VERTSPLIT
  2199.     if (col >= wp->w_width)        /* In separator line */
  2200.         on_sep_line = col - wp->w_width + 1;
  2201.     else
  2202.         on_sep_line = 0;
  2203.  
  2204.     /* The rightmost character of the status line might be a vertical
  2205.      * separator character if there is no connecting window to the right. */
  2206.     if (on_status_line && on_sep_line)
  2207.     {
  2208.         if (stl_connected(wp))
  2209.         on_sep_line = 0;
  2210.         else
  2211.         on_status_line = 0;
  2212.     }
  2213. #endif
  2214.  
  2215. #ifdef FEAT_VISUAL
  2216.     /* Before jumping to another buffer, or moving the cursor for a left
  2217.      * click, stop Visual mode. */
  2218.     if (VIsual_active
  2219.         && (wp->w_buffer != curwin->w_buffer
  2220.             || (!on_status_line
  2221. # ifdef FEAT_VERTSPLIT
  2222.             && !on_sep_line
  2223. # endif
  2224. # ifdef FEAT_FOLDING
  2225.             && (
  2226. #  ifdef FEAT_RIGHTLEFT
  2227.                 wp->w_p_rl ? col < W_WIDTH(wp) - wp->w_p_fdc :
  2228. #  endif
  2229.                 col >= wp->w_p_fdc
  2230. #  ifdef FEAT_CMDWIN
  2231.                   + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
  2232. #  endif
  2233.                 )
  2234. # endif
  2235.             && (flags & MOUSE_MAY_STOP_VIS))))
  2236.     {
  2237.         end_visual_mode();
  2238.         redraw_curbuf_later(INVERTED);    /* delete the inversion */
  2239.     }
  2240. #endif
  2241. #ifdef FEAT_CMDWIN
  2242.     if (cmdwin_type != 0 && wp != curwin)
  2243.     {
  2244.         /* A click outside the command-line window: Use modeless
  2245.          * selection if possible. */
  2246. # ifdef FEAT_CLIPBOARD
  2247.         return IN_OTHER_WIN;
  2248. # else
  2249.         row = 0;
  2250.         col += wp->w_wincol;
  2251.         wp = curwin;
  2252.         on_status_line = 0;
  2253.         on_sep_line = 0;
  2254. # endif
  2255.     }
  2256. #endif
  2257. #ifdef FEAT_WINDOWS
  2258.     win_enter(wp, TRUE);            /* can make wp invalid! */
  2259. # ifdef CHECK_DOUBLE_CLICK
  2260.     /* set topline, to be able to check for double click ourselves */
  2261.     if (curwin != old_curwin)
  2262.         set_mouse_topline(curwin);
  2263. # endif
  2264. #endif
  2265.     if (on_status_line)            /* In (or below) status line */
  2266.     {
  2267.         /* Don't use start_arrow() if we're in the same window */
  2268.         if (curwin == old_curwin)
  2269.         return IN_STATUS_LINE;
  2270.         else
  2271.         return IN_STATUS_LINE | CURSOR_MOVED;
  2272.     }
  2273. #ifdef FEAT_VERTSPLIT
  2274.     if (on_sep_line)            /* In (or below) status line */
  2275.     {
  2276.         /* Don't use start_arrow() if we're in the same window */
  2277.         if (curwin == old_curwin)
  2278.         return IN_SEP_LINE;
  2279.         else
  2280.         return IN_SEP_LINE | CURSOR_MOVED;
  2281.     }
  2282. #endif
  2283.  
  2284.     curwin->w_cursor.lnum = curwin->w_topline;
  2285. #ifdef FEAT_GUI
  2286.     /* remember topline, needed for double click */
  2287.     gui_prev_topline = curwin->w_topline;
  2288. # ifdef FEAT_DIFF
  2289.     gui_prev_topfill = curwin->w_topfill;
  2290. # endif
  2291. #endif
  2292.     }
  2293.     else if (on_status_line && which_button == MOUSE_LEFT)
  2294.     {
  2295. #ifdef FEAT_WINDOWS
  2296.     /* Drag the status line */
  2297.     count = row - curwin->w_winrow - curwin->w_height + 1 - on_status_line;
  2298.     win_drag_status_line(count);
  2299. #endif
  2300.     return IN_STATUS_LINE;            /* Cursor didn't move */
  2301.     }
  2302. #ifdef FEAT_VERTSPLIT
  2303.     else if (on_sep_line && which_button == MOUSE_LEFT)
  2304.     {
  2305.     /* Drag the separator column */
  2306.     count = col - curwin->w_wincol - curwin->w_width + 1 - on_sep_line;
  2307.     win_drag_vsep_line(count);
  2308.     return IN_SEP_LINE;            /* Cursor didn't move */
  2309.     }
  2310. #endif
  2311.     else /* keep_window_focus must be TRUE */
  2312.     {
  2313. #ifdef FEAT_VISUAL
  2314.     /* before moving the cursor for a left click, stop Visual mode */
  2315.     if (flags & MOUSE_MAY_STOP_VIS)
  2316.     {
  2317.         end_visual_mode();
  2318.         redraw_curbuf_later(INVERTED);    /* delete the inversion */
  2319.     }
  2320. #endif
  2321.  
  2322. #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
  2323.     /* Continue a modeless selection in another window. */
  2324.     if (cmdwin_type != 0 && row < W_WINROW(curwin))
  2325.         return IN_OTHER_WIN;
  2326. #endif
  2327.  
  2328.     row -= W_WINROW(curwin);
  2329. #ifdef FEAT_VERTSPLIT
  2330.     col -= W_WINCOL(curwin);
  2331. #endif
  2332.  
  2333.     /*
  2334.      * When clicking beyond the end of the window, scroll the screen.
  2335.      * Scroll by however many rows outside the window we are.
  2336.      */
  2337.     if (row < 0)
  2338.     {
  2339.         count = 0;
  2340.         for (first = TRUE; curwin->w_topline > 1; )
  2341.         {
  2342. #ifdef FEAT_DIFF
  2343.         if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
  2344.             ++count;
  2345.         else
  2346. #endif
  2347.             count += plines(curwin->w_topline - 1);
  2348.         if (!first && count > -row)
  2349.             break;
  2350.         first = FALSE;
  2351. #ifdef FEAT_FOLDING
  2352.         hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  2353. #endif
  2354. #ifdef FEAT_DIFF
  2355.         if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
  2356.             ++curwin->w_topfill;
  2357.         else
  2358. #endif
  2359.         {
  2360.             --curwin->w_topline;
  2361. #ifdef FEAT_DIFF
  2362.             curwin->w_topfill = 0;
  2363. #endif
  2364.         }
  2365.         }
  2366. #ifdef FEAT_DIFF
  2367.         check_topfill(curwin, FALSE);
  2368. #endif
  2369.         curwin->w_valid &=
  2370.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2371.         redraw_later(VALID);
  2372.         row = 0;
  2373.     }
  2374.     else if (row >= curwin->w_height)
  2375.     {
  2376.         count = 0;
  2377.         for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
  2378.         {
  2379. #ifdef FEAT_DIFF
  2380.         if (curwin->w_topfill > 0)
  2381.             ++count;
  2382.         else
  2383. #endif
  2384.             count += plines(curwin->w_topline);
  2385.         if (!first && count > row - curwin->w_height + 1)
  2386.             break;
  2387.         first = FALSE;
  2388. #ifdef FEAT_FOLDING
  2389.         if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
  2390.             && curwin->w_topline == curbuf->b_ml.ml_line_count)
  2391.             break;
  2392. #endif
  2393. #ifdef FEAT_DIFF
  2394.         if (curwin->w_topfill > 0)
  2395.             --curwin->w_topfill;
  2396.         else
  2397. #endif
  2398.         {
  2399.             ++curwin->w_topline;
  2400. #ifdef FEAT_DIFF
  2401.             curwin->w_topfill =
  2402.                    diff_check_fill(curwin, curwin->w_topline);
  2403. #endif
  2404.         }
  2405.         }
  2406. #ifdef FEAT_DIFF
  2407.         check_topfill(curwin, FALSE);
  2408. #endif
  2409.         redraw_later(VALID);
  2410.         curwin->w_valid &=
  2411.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2412.         row = curwin->w_height - 1;
  2413.     }
  2414.     else if (row == 0)
  2415.     {
  2416.         /* When dragging the mouse, while the text has been scrolled up as
  2417.          * far as it goes, moving the mouse in the top line should scroll
  2418.          * the text down (done later when recomputing w_topline). */
  2419.         if (mouse_dragging
  2420.             && curwin->w_cursor.lnum
  2421.                        == curwin->w_buffer->b_ml.ml_line_count
  2422.             && curwin->w_cursor.lnum == curwin->w_topline)
  2423.         curwin->w_valid &= ~(VALID_TOPLINE);
  2424.     }
  2425.     }
  2426.  
  2427. #ifdef FEAT_FOLDING
  2428.     /* Check for position outside of the fold column. */
  2429.     if (
  2430. # ifdef FEAT_RIGHTLEFT
  2431.         curwin->w_p_rl ? col < W_WIDTH(curwin) - curwin->w_p_fdc :
  2432. # endif
  2433.         col >= curwin->w_p_fdc
  2434. #  ifdef FEAT_CMDWIN
  2435.                 + (cmdwin_type == 0 ? 0 : 1)
  2436. #  endif
  2437.        )
  2438.     mouse_char = ' ';
  2439. #endif
  2440.  
  2441.     /* compute the position in the buffer line from the posn on the screen */
  2442.     if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum))
  2443.     mouse_past_bottom = TRUE;
  2444.  
  2445. #ifdef FEAT_VISUAL
  2446.     /* Start Visual mode before coladvance(), for when 'sel' != "old" */
  2447.     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
  2448.     {
  2449.     check_visual_highlight();
  2450.     VIsual = old_cursor;
  2451.     VIsual_active = TRUE;
  2452.     VIsual_reselect = TRUE;
  2453.     /* if 'selectmode' contains "mouse", start Select mode */
  2454.     may_start_select('o');
  2455.     setmouse();
  2456.     if (p_smd)
  2457.         redraw_cmdline = TRUE;    /* show visual mode later */
  2458.     }
  2459. #endif
  2460.  
  2461.     curwin->w_curswant = col;
  2462.     curwin->w_set_curswant = FALSE;    /* May still have been TRUE */
  2463.     if (coladvance(col) == FAIL)    /* Mouse click beyond end of line */
  2464.     {
  2465.     if (inclusive != NULL)
  2466.         *inclusive = TRUE;
  2467.     mouse_past_eol = TRUE;
  2468.     }
  2469.     else if (inclusive != NULL)
  2470.     *inclusive = FALSE;
  2471.  
  2472.     count = IN_BUFFER;
  2473.     if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
  2474.         || curwin->w_cursor.col != old_cursor.col)
  2475.     count |= CURSOR_MOVED;        /* Cursor has moved */
  2476.  
  2477. #ifdef FEAT_FOLDING
  2478.     if (mouse_char == '+')
  2479.     count |= MOUSE_FOLD_OPEN;
  2480.     else if (mouse_char != ' ')
  2481.     count |= MOUSE_FOLD_CLOSE;
  2482. #endif
  2483.  
  2484.     return count;
  2485. }
  2486.  
  2487. /*
  2488.  * Compute the position in the buffer line from the posn on the screen in
  2489.  * window "win".
  2490.  * Returns TRUE if the position is below the last line.
  2491.  */
  2492.     int
  2493. mouse_comp_pos(win, rowp, colp, lnump)
  2494.     win_T    *win;
  2495.     int        *rowp;
  2496.     int        *colp;
  2497.     linenr_T    *lnump;
  2498. {
  2499.     int        col = *colp;
  2500.     int        row = *rowp;
  2501.     linenr_T    lnum;
  2502.     int        retval = FALSE;
  2503.     int        off;
  2504.     int        count;
  2505.  
  2506. #ifdef FEAT_RIGHTLEFT
  2507.     if (win->w_p_rl)
  2508.     col = W_WIDTH(win) - 1 - col;
  2509. #endif
  2510.  
  2511.     lnum = win->w_topline;
  2512.  
  2513.     while (row > 0)
  2514.     {
  2515. #ifdef FEAT_DIFF
  2516.     /* Don't include filler lines in "count" */
  2517.     if (win->w_p_diff && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL))
  2518.     {
  2519.         if (lnum == win->w_topline)
  2520.         row -= win->w_topfill;
  2521.         else
  2522.         row -= diff_check_fill(win, lnum);
  2523.         count = plines_win_nofill(win, lnum, TRUE);
  2524.     }
  2525.     else
  2526. #endif
  2527.         count = plines_win(win, lnum, TRUE);
  2528.     if (count > row)
  2529.     {
  2530.         /* Position is in this buffer line.  Compute the column
  2531.          * without wrapping. */
  2532.         off = win_col_off(win) - win_col_off2(win);
  2533.         if (col < off)
  2534.         col = off;
  2535.         col += row * (W_WIDTH(win) - off);
  2536.         /* add skip column (for long wrapping line) */
  2537.         col += win->w_skipcol;
  2538.         break;
  2539.     }
  2540. #ifdef FEAT_FOLDING
  2541.     (void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
  2542. #endif
  2543.     if (lnum == win->w_buffer->b_ml.ml_line_count)
  2544.     {
  2545.         retval = TRUE;
  2546.         break;        /* past end of file */
  2547.     }
  2548.     row -= count;
  2549.     ++lnum;
  2550.     }
  2551.  
  2552.     if (!win->w_p_wrap)
  2553.     col += win->w_leftcol;
  2554.  
  2555.     /* skip line number and fold column in front of the line */
  2556.     col -= win_col_off(win);
  2557.     if (col < 0)
  2558.     col = 0;
  2559.  
  2560.     *colp = col;
  2561.     *rowp = row;
  2562.     *lnump = lnum;
  2563.     return retval;
  2564. }
  2565.  
  2566. #ifdef FEAT_WINDOWS
  2567. /*
  2568.  * Find the window at screen position "*rowp" and "*colp".  The positions are
  2569.  * updated to become relative to the top-left of the window.
  2570.  */
  2571. /*ARGSUSED*/
  2572.     win_T *
  2573. mouse_find_win(rowp, colp)
  2574.     int        *rowp;
  2575.     int        *colp;
  2576. {
  2577.     frame_T    *fp;
  2578.  
  2579.     fp = topframe;
  2580.     for (;;)
  2581.     {
  2582.     if (fp->fr_layout == FR_LEAF)
  2583.         break;
  2584. #ifdef FEAT_VERTSPLIT
  2585.     if (fp->fr_layout == FR_ROW)
  2586.     {
  2587.         for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
  2588.         {
  2589.         if (*colp < fp->fr_width)
  2590.             break;
  2591.         *colp -= fp->fr_width;
  2592.         }
  2593.     }
  2594. #endif
  2595.     else    /* fr_layout == FR_COL */
  2596.     {
  2597.         for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
  2598.         {
  2599.         if (*rowp < fp->fr_height)
  2600.             break;
  2601.         *rowp -= fp->fr_height;
  2602.         }
  2603.     }
  2604.     }
  2605.     return fp->fr_win;
  2606. }
  2607. #endif
  2608.  
  2609. #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined (FEAT_GUI_MAC) \
  2610.     || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
  2611.     || defined(FEAT_GUI_PHOTON) || defined(PROTO)
  2612. /*
  2613.  * Translate window coordinates to buffer position without any side effects
  2614.  */
  2615.     int
  2616. get_fpos_of_mouse(mpos)
  2617.     pos_T    *mpos;
  2618. {
  2619.     win_T    *wp;
  2620.     int        count;
  2621.     char_u    *ptr;
  2622.     int        row = mouse_row;
  2623.     int        col = mouse_col;
  2624.  
  2625.     if (row < 0 || col < 0)        /* check if it makes sense */
  2626.     return IN_UNKNOWN;
  2627.  
  2628. #ifdef FEAT_WINDOWS
  2629.     /* find the window where the row is in */
  2630.     wp = mouse_find_win(&row, &col);
  2631. #else
  2632.     wp = firstwin;
  2633. #endif
  2634.     /*
  2635.      * winpos and height may change in win_enter()!
  2636.      */
  2637.     if (row >= wp->w_height)    /* In (or below) status line */
  2638.     return IN_STATUS_LINE;
  2639. #ifdef FEAT_VERTSPLIT
  2640.     if (col >= wp->w_width)    /* In vertical separator line */
  2641.     return IN_SEP_LINE;
  2642. #endif
  2643.  
  2644.     if (wp != curwin)
  2645.     return IN_UNKNOWN;
  2646.  
  2647.     /* compute the position in the buffer line from the posn on the screen */
  2648.     if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum))
  2649.     return IN_STATUS_LINE; /* past bottom */
  2650.  
  2651.     /* try to advance to the specified column */
  2652.     mpos->col = 0;
  2653.     count = 0;
  2654.     ptr = ml_get_buf(wp->w_buffer, mpos->lnum, FALSE);
  2655.     while (count <= col && *ptr != NUL)
  2656.     {
  2657.     ++mpos->col;
  2658.     count += win_lbr_chartabsize(wp, ptr, count, NULL);
  2659. #ifdef FEAT_MBYTE
  2660.     if (has_mbyte)
  2661.         ptr += (*mb_ptr2len_check)(ptr);
  2662.     else
  2663. #endif
  2664.         ++ptr;
  2665.     }
  2666.     if (mpos->col == 0)
  2667.     return IN_BUFFER;
  2668.     --mpos->col;
  2669.     return IN_BUFFER;
  2670. }
  2671. #endif
  2672.  
  2673. #endif /* FEAT_MOUSE */
  2674.  
  2675. #if defined(FEAT_GUI) || defined(WIN3264) || defined(PROTO)
  2676. /*
  2677.  * Called when focus changed.  Used for the GUI or for systems where this can
  2678.  * be done in the console (Win32).
  2679.  */
  2680.     void
  2681. ui_focus_change(in_focus)
  2682.     int        in_focus;    /* TRUE if focus gained. */
  2683. {
  2684.     static time_t    last_time = (time_t)0;
  2685.     int            need_redraw = FALSE;
  2686.  
  2687.     /* When activated: Check if any file was modified outside of Vim.
  2688.      * Only do this when not done within the last two seconds (could get
  2689.      * several events in a row). */
  2690.     if (in_focus && last_time + 2 < time(NULL))
  2691.     {
  2692.     need_redraw = check_timestamps(
  2693. # ifdef FEAT_GUI
  2694.         gui.in_use
  2695. # else
  2696.         FALSE
  2697. # endif
  2698.         );
  2699.     last_time = time(NULL);
  2700.     }
  2701.  
  2702. #ifdef FEAT_AUTOCMD
  2703.     /*
  2704.      * Fire the focus gained/lost autocommand.
  2705.      */
  2706.     need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED
  2707.                 : EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf);
  2708. #endif
  2709.  
  2710.     if (need_redraw)
  2711.     {
  2712.     /* Something was executed, make sure the cursor is put back where it
  2713.      * belongs. */
  2714.     need_wait_return = FALSE;
  2715.  
  2716.     if (State & CMDLINE)
  2717.         redrawcmdline();
  2718.     else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
  2719.         || State == EXTERNCMD || State == CONFIRM || exmode_active)
  2720.         repeat_message();
  2721.     else if ((State & NORMAL) || (State & INSERT))
  2722.     {
  2723.         if (must_redraw != 0)
  2724.         update_screen(0);
  2725.         setcursor();
  2726.     }
  2727.     cursor_on();        /* redrawing may have switched it off */
  2728.     out_flush();
  2729. # ifdef FEAT_GUI
  2730.     if (gui.in_use)
  2731.     {
  2732.         gui_update_cursor(FALSE, TRUE);
  2733.         gui_update_scrollbars(FALSE);
  2734.     }
  2735. # endif
  2736.     }
  2737. #ifdef FEAT_TITLE
  2738.     /* File may have been changed from 'readonly' to 'noreadonly' */
  2739.     if (need_maketitle)
  2740.     maketitle();
  2741. #endif
  2742. }
  2743. #endif
  2744.  
  2745. #if defined(USE_IM_CONTROL) || defined(PROTO)
  2746. /*
  2747.  * Save current Input Method status to specified place.
  2748.  */
  2749.     void
  2750. im_save_status(psave)
  2751.     long *psave;
  2752. {
  2753.     /* Don't save when 'imdisable' is set or "xic" is NULL, IM is always
  2754.      * disabled then (but might start later).
  2755.      * Also don't save when inside a mapping, vgetc_im_active has not been set
  2756.      * then. */
  2757.     if (!p_imdisable && KeyTyped
  2758. # ifdef FEAT_XIM
  2759.         && xic != NULL
  2760. # endif
  2761.     )
  2762.     {
  2763.     /* Do save when IM is on, or IM is off and saved status is on. */
  2764.     if (vgetc_im_active)
  2765.         *psave = B_IMODE_IM;
  2766.     else if (*psave == B_IMODE_IM)
  2767.         *psave = B_IMODE_NONE;
  2768.     }
  2769. }
  2770. #endif
  2771.